#include <stdio.h>
#include <stdlib.h>

#include "Tree.h"

#define IF_FAIL(X) if(X){printf("FAIL IN %s TEST, IN LINE %d\n",#X,__LINE__); return 1;}
typedef struct Person
{
    int age;
    char name[30];
}Person;

int PersonLess(void* _a, void* _b)
{
    return ((Person*)_a)->age < ((Person*)_b)->age;
}

int LessFunction(void* _a , void* _b)
{
    return *(int*)_a < *(int*)_b ;
}

int TreeRemove_Utest();

int main()
{
    Tree* tree = TreeNew(PersonLess);
    TreeIter it;
    TreeIter it1;
    TreeIter it2;
    TreeIter it3;
    TreeIter it4;
    TreeIter it5;
    Person p1 = {33, "avi"};
    Person p2 = {44, "boby"};
    Person p3 = {11, "coco"};
    Person p4 = {5, "dado"};
    Person p5 = {22, "shoko"};
    Person ptest;

    /*  do rand ages    */
    IF_FAIL(!TreeIsEmpty(tree))     /*  Check tree is empty */

    it1  = TreeInsert(tree, &p1);
    IF_FAIL(TreeIsEmpty(tree))      /*  Check that now tree isn't empty */
    it2 = TreeInsert(tree, &p2);
    it4 = TreeInsert(tree, &p4);
    it3 = TreeInsert(tree, &p3);

    IF_FAIL(TreeGetData(it1) != &p1)                    /*  Check that iterator are corect, and check GetData                   */
    IF_FAIL(TreeBegin(tree) != it4)                     /*  Check that begin points to the beginning                            */

    ptest.age = 5;
    IF_FAIL(TreeFind(tree, &ptest) != it4)              /*  Check TreeFind return the right iterator                            */
    ptest.age = 3;                                      /*  Put not exist value                                                 */
    IF_FAIL(TreeFind(tree, &ptest) != TreeEnd(tree))    /*  Check that end iterator return                                      */
    IF_FAIL(!TreeIsEqual(TreeBegin(tree), it4))         /*  Chek TreeEqual work                                                 */

    IF_FAIL(!TreeIsEqual(TreeNext(it2), TreeEnd(tree))) /*  Checks tree next                                                    */
    IF_FAIL(!TreeIsEqual(TreeNext(it4), it3))
    IF_FAIL(!TreeIsEqual(TreeNext(it1), it2))

    IF_FAIL(!TreeIsEqual(TreePrev(it2), it1))           /*  Checks tree prev                                                    */
    IF_FAIL(!TreeIsEqual(TreePrev(it3), TreeBegin(tree)))
    IF_FAIL(!TreeIsEqual(TreePrev(it1), it3))
    IF_FAIL(!TreeIsEqual(TreePrev(TreeEnd(tree)), it2))

    it5 = TreeInsert(tree, &p5);

    for(it = TreeBegin(tree); !TreeIsEqual(it, TreeEnd(tree)); it = TreeNext(it))
    {
        printf("The age of %s is: %d\n", ((Person*)TreeGetData(it))->name, ((Person*)TreeGetData(it))->age);
    }

    puts("");
    it = TreeNext(TreeBegin(tree));
    IF_FAIL(!TreeIsEqual(it, TreeRemove(tree, TreeBegin(tree)) ) );               /*  Check we get the next after remove  */
    ptest.age = 5;
    IF_FAIL(!TreeIsEqual(TreeFind(tree, &ptest), TreeEnd(tree)))    /*  Check that the lowest data removed  */

    TreeRemove(tree, it);

    TreeRemove(tree, TreeBegin(tree));

    TreeRemove(tree, TreeBegin(tree));

    TreeRemove(tree, TreeBegin(tree));

    IF_FAIL(!TreeIsEmpty(tree))                                     /*  Check that after all removed tree is empty  */

    for(it = TreeBegin(tree); !TreeIsEqual(it, TreeEnd(tree)); it = TreeNext(it))
    {
        printf("The age of %s is: %d\n", ((Person*)TreeGetData(it))->name, ((Person*)TreeGetData(it))->age);
    }

    TreeDel(tree);

    TreeRemove_Utest();

    return 0;
}


int TreeRemove_Utest()
{
    int arr[] = {8,10,5,2,7,9,12,11,15,6,0,1,3,13,4,14};
    Tree* tree = TreeNew(LessFunction);
    TreeIter it , itRm;
    TreeIter itArr[16];
    int rmNum;
    int i, j;
    int next;

    itArr[0] = TreeInsert(tree, &arr[0]);
    IF_FAIL(!TreeIsEqual(TreePrev(TreeEnd(tree)), itArr[0]))
    IF_FAIL(!TreeIsEqual(TreeRemove(tree, itArr[0]), TreeEnd(tree)))    /*  Check removal of root   */

    itArr[0] = TreeInsert(tree, &arr[10]);   /*  insert 0    */
    IF_FAIL(!TreeIsEqual(TreePrev(TreeEnd(tree)), itArr[0]))
    itArr[1] = TreeInsert(tree, &arr[11]);   /*  insert 3    */
    itArr[0] = TreeRemove(tree, itArr[0]);
    IF_FAIL(!TreeIsEqual(itArr[0], itArr[1]))    /*  Check removal of root, returns 3   */
    IF_FAIL(!TreeIsEqual(itArr[0], TreeBegin(tree)))    /*  Check removal of root, returns 3   */

    TreeRemove(tree, itArr[0]);

    for(it = TreeBegin(tree); !TreeIsEqual(it, TreeEnd(tree)); it = TreeNext(it))
    {
        printf("The number is: %d\n", *((int*)TreeGetData(it)));
    }


    for(i = 0; i < sizeof(arr)/sizeof(int); ++i)
    {
        itArr[i] = TreeInsert(tree, &arr[i]);
    }


    /*  `Now the tree is:
                                            8

                            5                                   10

                    2               7                     9           12

                0       3       6                                11         15

                      1    4                                             13

                                                                            14
*/

    IF_FAIL(!TreeIsEqual(TreePrev(TreeEnd(tree)), itArr[8]))

    for(i = 0; i < 16; ++i)
    {
        itRm = TreeFind(tree, &arr[i]);
        rmNum = *((int*)TreeGetData(itRm));
        if(!TreeIsEqual(TreeNext(itRm), TreeEnd(tree)))
        {
            next = *((int*)TreeGetData(TreeNext(itRm)));
            IF_FAIL(next !=  *((int*)TreeGetData(TreeRemove(tree, itRm)  )));
        }
        else
        {
            IF_FAIL(!TreeIsEqual(TreeEnd(tree), TreeRemove(tree, itRm)))
        }
        for(it = TreeBegin(tree), j = 0; !TreeIsEqual(it, TreeEnd(tree)); it = TreeNext(it), ++j)
        {
            if(j == rmNum)
            {
                ++j;
            }

            printf("The number is: %d\n", *((int*)TreeGetData(it)));
            IF_FAIL(*((int*)TreeGetData(it)) != j)
        }
        puts("");
        for(it = TreePrev(TreeEnd(tree)), j = 15; !TreeIsEqual(it, TreeBegin(tree)); it = TreePrev(it), --j)
        {
            if(j == rmNum)
            {
                --j;
            }
            IF_FAIL(*((int*)TreeGetData(it)) != j)

            printf("The number is: %d\n", *((int*)TreeGetData(it)));
        }
        printf("The number is: %d\n", *((int*)TreeGetData(TreeBegin(tree))));
        if(j == rmNum)
        {
            --j;
        }
        IF_FAIL(*((int*)TreeGetData(it)) != j)
        puts("");
        TreeInsert(tree, &arr[i]);


    }

    return 0;
}
